perm filename TCPBFR.MAC[IP,SYS] blob sn#680217 filedate 1982-10-14 generic text, type T, neo UTF8
;CWL:<403-TCP>TCPBFR.MAC.40303 26-Apr-82 16:38:31, Edit by CLYNN
;<403-TCP>TCPBFR.MAC.40301 29-Jan-82 15:00:39, Edit by CLYNN
; Updated for TCP release 3

	SEARCH	INPAR,TCPPAR,PROLOG
	TTITLE	TCPBFR
	SUBTTL	TCP Buffer handling routines, Wm. W. Plummer, 15MAR77
	SWAPCD


	DEFAC (FX,Q3)		; Must agree with PROLOG, PAGEM
IFKA <	DEFSTR FKUPT,FKPGS(FX),17,18>	; SPT index of user mode page table


COMMENT	!

	These are routines for mapping, reading, and writing buffers.
	Buffers are actually in the address space of the fork executing
	a SEND or RECV, but are manipuated by the TCP fork.  Data is
	copied only once, directly from (or to) the buffer into a packet
	(or vice versa).

	Since the TCP fork must guard against the page(s) containing
	the buffer disappearing (unmapped, fork killed, etc), it
	increments the share count on the SPT slot containing the
	calling fork's UPT.  This prevents the map from going away.
	Subsequent access checking will discover that the
	page is missing and approriate errors returned.

	SEND and RECV buffer headers are actually formed by the MAKBFR
	routine in TCPJS.  They are queued on TCBSBQ or TCBRBQ for
	action by the Packetizer or Reassembler.

* SETTUM ...  3 ...... Set TCP fork's user map (begin NOSKED)
* USTTUM ...  4 ...... Unset the above (end NOSKED)
* RSTBFR ...  5 ...... Reset buffer variables to virgin state
* XFRDAT ...  6 ...... Transfer data between user buf and pkt
* TBFINI ... 10 ...... TCP buffer initialization

	!
; SETTUM(BFR)		Set TCP fork's user map to be that of the buffer

; This routine is called by the Packetizer and Reassembler (TCPUSR) to get
; the current page of a buffer mapped so it can reference the data in it.

;BFR/	(Extended) Pointer to the current buffer descriptor block
;
;	CALL SETTUM
;Ret+1:	Always. NOSKED

SETTUM::PUSH P,FX
	NOSKED			; Prevent user from changing access
	LOAD FX,BFRKX,(BFR)	; Get the fork which owns the buffer
IFKA <	MOVE T1,FORKX		; Internet fork runs TCP
	MOVE T1,FKPGS(T1)	; Pick up UPT,,PSB
	MOVEM T1,TCPUS0		; Save that for later
	LOAD T1,FKUPT		; Get SPT index of page table
	CALL UPSHR		; Keep it from going away
	LOAD T1,FKUPT		; Get SPT index of page table
	MOVE FX,FORKX		; Now talk about this fork
	STOR T1,FKUPT		; Set user space as our user space
	DPB T1,[POINT 13,PSB+UPTPG,26]	; Store in our monitor mode map
	CALL SETPPG		; Set up the pager
	JSP T1,[TXZ T1,PC%CFM	; Clear call from monitor flag
		JRSTF (T1)]
>
IFNKA <	MOVE T1,USECTB+0	; TCP's user section 0
	MOVEM T1,TCPUS0		; Save that for later
	LOAD T1,FKUPT		; Get SPT index of page table
	CALL UPSHR		; Keep it from going away
	LOAD T1,FKUPT		; Get SPT index of page table
	MOVE T2,SHRPTR		; Prototype share pointer
	STOR T1,SPTX,T2		; To that SPT slot
	MOVEM T2,USECTB+0	; Place in process table
	DATAI PAG,T1		; Get current pager status (UBA)
	TXZ T1,PGLACB+PGLPCS	; Be sure these control bits are off
	TXO T1,PGLUBR		; Say we want to load the UBA
	DATAO PAG,T1		; Which invalidates stale info in map


  IFSM <JSP T1,[TXO T1,PCU	; Turn on previous context user bit
		JRSTF (T1)]
  >
  IFKL <JSP T2,[XSFM T1		; Store processor flags
		TXO T1,PCU	; Previous context user bit
		XJRSTF T1]	; Return with PCU set so XCTU works
  >
>
	POP P,FX
	RET
; USTTUM(BFR)		Unmap user space

;BFR/	(Extended) pointer to buffer descriptor block
; NOSKED
;
;	CALL USTTUM
;Ret+1:	Always.  Returns OKSKED

USTTUM::PUSH P,FX		; Used by FKUPT
	MOVE T1,TCPUS0		; The TCP's actual user secton 0
IFKA <	MOVE FX,FORKX		; Get our own fork number
	MOVEM T1,FKPGS(FX)	; Restore our user mode map
	LOAD T1,FKUPT		; Get the UPT
	DPB T1,[POINT 13,PSB+UPTPG,26]	; Change our map
	CALL SETPPG		; Gunch the pager
	LOAD FX,BFRKX,(BFR)	; Get the owning fork
	LOAD T1,FKUPT		; Get SPT index of that fork's map
	CALL DWNSHR
	JSP T1,[TXO T1,PC%CFM	; Turn off previous context monitor bit
		JRSTF (T1)]
>
IFNKA <	MOVEM T1,USECTB+0	; Put back in process table
	DATAI PAG,T1
	TXZ T1,PGLACB+PGLPCS
	TXO T1,PGLUBR
	DATAO PAG,T1		; Cause pager to look again
	LOAD FX,BFRKX,(BFR)	; Get the owning fork
	LOAD T1,FKUPT		; Get SPT index of that fork's map
	CALL DWNSHR
>
  IFSM <JSP T1,[TXZ T1,PCU	; Turn off previous context user bit
		JRSTF (T1)]
  >
  IFKL <JSP T2,[XSFM T1		; Get flags
		TXZ T1,PCU	; Turn off PCU bit
		XJRSTF T1]
  >
	OKSKED
	POP P,FX
	RET

; RSTBFR(BFR)			Reset a buffer (descriptor block)

;BFR/	(Extended) Pointer to the buffer descriptor
;
;	CALL RSTBFR
;Ret+1:	Always.

RSTBFR::LOAD T1,BICNT,(BFR)	; Initial byte/word cnt set by SEND, etc
	STOR T1,BCNT,(BFR)	; Set as the working countdown
	LOAD T1,BDADR,(BFR)	; Data address in user space
	STOR T1,BPTRA,(BFR)	; Set buffer byte pointer address
	MOVEI T1,↑D36
	STOR T1,BPTRP,(BFR)	; Set position field
	RET
; XFRDAT	Transfer data between user buffer and a packet

;T1/	Source pointer (may index by TPKT)
;T2/	Dest pointer (may index by TPKT)
;T3/	Number of 8-bit bytes to transfer
;T4/	Non-0 says User-to-monitor transfer (Send direction)
;
;	CALL XFRDAT
;Ret+1:	Always.  T1, T2, T3 updated

;This is a cutdown version of BYTBLT which assumes 8-bit bytes and is
;able to cope with the source or destination pointers
;indexing by TPKT which is required to get extended addressing.

XFRDAT::LOCAL <SRC,DEST,CNT,CNT2>
	PUSH P,FR
	MOVE FR,T4		; Save the Send flag
	SKIPG CNT,T3		; Move count and test for early done
	 JRST XFRDAZ		; Zero byte move
	DMOVEM T1,SRC		; T1 to SRC and T2 to DEST
	CAIG CNT,20		; Short transfer? (must be ge 10!)
	 JRST XFRDA1		; Yes
	XOR T1,T2		; Set to compare
	TLC T2,(10B11)		; Flip the byte size
	TLNN T1,(77B11)		; Byte sizes agree?
	TLNE T2,(77B11)		; And both are 8?
	CAIA			; Something is fishy
	 JRST XFRDA3		; Go do it word-at-a-time
	TCPBUG (CHK,<XFRDAT: Byte size screwed up>,TCPMSX)

; Byte-at-a-time mover.  Use Extended Instruction Set if present.

XFRDA1:	REPEAT 0,<	; This doesn't work on the 2020.  (Why?)
	IFNKA <
	CAIG CNT,4		; Is setup for MOVSLJ worth it?
	 JRST XFRDA2		; No.
	PUSH P,FR		; Save send flag
	MOVE FR,CNT		; Set source count
	MOVE T1,SRC		; Source ptr (local ptr, T2 not used)
	MOVE T3,CNT		; Set dest count
	MOVE T4,DEST		; Dst pointer (local ptr, T4+1 not used)
	SKIPN 0(P)		; Skip if send direction
	 JRST XFRD11
	XCT 2,[	EXTEND [MOVSLJ]]
XFRD10:	 TCPBUG (CHK,<XFRDAT: MOVSLJ failure>,TCPMSY)
	JRST XFRD12

XFRD11:	XCT 1,[	EXTEND [MOVSLJ]]
	 JRST XFRD10
XFRD12:	POP P,FR		; Recover flag
	MOVE SRC,T1		; Get updated source pointer
	MOVE DEST,T4		; Get updated dst pointer
	JRST XFRDAX		; and get out
	>
>

; Here for byte-at-a-time move when EIS not on the machine.  Also
; used to finish up after other move routines.

XFRDA2:	JUMPE FR,XFRD21		; Jump if receive direction
XFRD20:	XCTBU [	ILDB T1,SRC]	; Get a source byte
	IDPB T1,DEST		; Put it where it belongs
	SOJG CNT,XFRD20		; Loop til done
	JRST XFRDAX		; Return to caller

XFRD21:	ILDB T1,SRC
	XCTBU [	IDPB T1,DEST]
	SOJG CNT,XFRD21
	JRST XFRDAX

; Word-at-a-time movers.  Use BLT if no offset in positions.

XFRDA3:	TLNN DEST,(7B2)		; Not up to a word boundary yet?
	TLNE SRC,(1B0)		; Or SRC is a 4410XX style pointer?
	CAIA			; Yes.  Bump both pointers.
	 JRST XFRDA4		; No
	JUMPE FR,XFRD31		; Jump if receive direction
	XCTBU [ILDB T1,SRC]		; No. Move a few bytes til so
	IDPB T1,DEST
	SOJA CNT,XFRDA3		; Note CNT starts ge 10

XFRD31:	ILDB T1,SRC		; No. Move a few bytes til so
	XCTBU [IDPB T1,DEST]
	SOJA CNT,XFRDA3		; Note CNT starts ge 10

XFRDA4:	PUSH P,SRC		; Save pointers so left half can be
	PUSH P,DEST		; restored after using as local indirect
	LDB T1,[POINT 3,SRC,2]	; Position will be 04, 14, 24, or 34
	TXZ SRC,-1B12		; Clear reserved bits
	TXZ DEST,-1B12
	TXO SRC,IFIW		; Form local indirect pointers
	TXO DEST,IFIW
	IDIVI CNT,↑D<36/8>	; Number of full words to move
	JUMPE T1,XFRDA8		; No offset in position.  Use BLT

; Offset move

XFRDA5:	ASH T1,3		; Number of bits present in T1
	MOVNI T3,-↑D36(T1)	; Amount of shift required in loop
	MOVNI T4,-↑D32(T3)	; Number left in T2 after 1st LSH
	SKIPN FR		; Sending?
	 SKIPA T1,@SRC		; No.  Source is monitor space
	 UMOVE T1,@SRC		; Get 1st source word
	ADDI SRC,1		; Bump (extended) pointer
	LSH T1,-4		; Flush the extra bits
; Main move-shift loop (should be in ACs on KA10)

XFRDA6:	SKIPN FR		; Skip if send-direction
	 SKIPA T2,@SRC		; Get four more bytes
	 UMOVE T2,@SRC		; Get four more bytes
	ADDI SRC,1		; Bump extended indirect word
	LSHC T1,0(T3)		; Fill out 32 T1 bits and left justify
	ADDI DEST,1		; Advance destination indirect word
	SKIPN FR		; Skip if sending
	 UMOVEM T1,@DEST	; Store away
	SKIPE FR		; Skip if receiving
	 MOVEM T1,@DEST		; Store away
	LSHC T1,0(T4)		; Get rest from T2 and right just. in T1
	SOJG CNT,XFRDA6		; Loop over all full words
	POP P,T2		; Original DEST
	POP P,T1		; Original SRC
	HLL SRC,T1		; Restore position and size fields
	HLL DEST,T2		; Index and indirect bits wont change
	SOJA SRC,XFRDA9		; Undo the last increment

; No offset.  SRC and DEST were 0410xx,,Y-1


XFRDA8:	MOVE T1,CNT		; Get count
	XMOVEI T2,@SRC		; Get source address
	XMOVEI T3,@DEST		; and Destination
	ADDI T2,1		; Byte ptrs were at end of previous word
	ADDI T3,1
	JUMPN FR,XFRD81		; Jump if receiving
	HRRZS T3		; Sending.  Dest is user section 0
	CALL BLTMU		; Move to user
	JRST XFRD82
XFRD81:	HRRZS T2		; Source is user section 0
	CALL BLTUM
XFRD82:	POP P,DEST		; Original DEST
	POP P,SRC		; Original SRC
	ADD SRC,CNT
	ADD DEST,CNT		; Advance pointers


; Exit for word-at-a-time movers.

XFRDA9:	SKIPE CNT,CNT2		; Number left in partial word
	 JRST XFRDA2		; Go finish them and return

; Common exit

XFRDAX:	DMOVE T1,SRC		; Get updated pointers
	SETZ T3,		; Return a count of 0
XFRDAZ:	POP P,FR
	RESTORE
	RET

; TBFINI			Buffer initialization code

; Called only at startup

;	CALL TBFINI
;Ret+1:	Always.

TBFINI::RET			; Nothing to do in this version



	TNXEND